package com.cdelink.xzgy.ftp.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cdelink.xzgy.ftp.common.Constants;
import com.cdelink.xzgy.ftp.common.ReturnData;
import com.cdelink.xzgy.ftp.exception.BaseException;
import com.cdelink.xzgy.ftp.exception.InvalidDataException;
import com.cdelink.xzgy.ftp.user.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;

import static com.cdelink.xzgy.ftp.common.ReturnData.CODE_FAIL_CACHE_TOKEN;

/**
 *
 */
public class JwtUtil {
    static final Logger LOGGER = LoggerFactory.getLogger(JwtUtil.class);
    public static final String KEY_USER_TOKEN = "user_token";
    public static final String KEY_USER_ID = "user_id";

    static final String ISSUER = "recall-admin";
    static final Algorithm ALGORITHM = Algorithm.HMAC256("recall-admin-2021");

    private JwtUtil() {
    }

    /**
     * 基于JWT创建用户Token
     *
     * @param user 用户对象
     * @return token
     */
    public static String generateUserToken(User user, RedisUtil redisUtil) {
        Calendar cal = Calendar.getInstance();
        Date issued = cal.getTime();
        //有效期设置为2小时
        cal.add(Calendar.HOUR, 2);
        Date expired = cal.getTime();
        JWTCreator.Builder builder = JWT.create()
                .withIssuer(ISSUER)
                .withIssuedAt(issued)
                .withExpiresAt(expired)
                .withClaim(KEY_USER_ID, user.getId());
        String token = builder.sign(ALGORITHM);
        if (!cacheUserToken(redisUtil, user, token)) {
            throw new BaseException(CODE_FAIL_CACHE_TOKEN, null);
        }
        return token;
    }

    /**
     * 解析用户 token。
     *
     * @param userToken 用户token
     * @return 用户对象
     */
    public static User decodeUserToken(String userToken) {
        DecodedJWT djwt = verifyToken(userToken);
        Integer userId = djwt.getClaim(KEY_USER_ID).asInt();
        if (userId == null) {
            LOGGER.error("用户登录无效");
            return null;
        }
        User user = new User();
        user.setId(userId);
        return user;
    }

    static DecodedJWT verifyToken(String token) {
        JWTVerifier verifier = JWT.require(ALGORITHM).withIssuer(ISSUER).build();
        try {
            return verifier.verify(token);
        } catch (TokenExpiredException expired) {
            throw new BaseException(ReturnData.CODE_FORBIDDEN, "登录已过期，请重新登录");
        }
    }
    /**
     * 缓存用户token
     * @param user
     * @param token
     * @return
     */
    static boolean cacheUserToken(RedisUtil redisUtil, User user, String token) {
        if (token.length() < RedisUtil.USER_TOKEN_CACHE_LEN) {
            throw new InvalidDataException("Token长度无效");
        }
        //设置redis缓存，并设置过期时间
        return redisUtil.set(String.format(RedisUtil.KEY_USER_ID,user.getId() ),
                token.substring(token.length() - RedisUtil.USER_TOKEN_CACHE_LEN),
                Constants.USER_SESSION_IDLE_DURATION);
    }

}
